[IA64] SMP-guest
authorawilliam@xenbuild.aw <awilliam@xenbuild.aw>
Fri, 21 Apr 2006 16:40:17 +0000 (10:40 -0600)
committerawilliam@xenbuild.aw <awilliam@xenbuild.aw>
Fri, 21 Apr 2006 16:40:17 +0000 (10:40 -0600)
Final SMP-guest patch: add IPI and boot rendez-vous support.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c
linux-2.6-xen-sparse/arch/ia64/xen/hypercall.S
xen/arch/ia64/xen/dom_fw.c
xen/arch/ia64/xen/hypercall.c
xen/include/asm-ia64/dom_fw.h

index 647b0ca608043d45bdc07cbb46945e8886c4e850..4f72108eb4bcb70304dc4533e7924226578f966b 100644 (file)
@@ -265,6 +265,14 @@ ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
        unsigned long ipi_data;
        unsigned long phys_cpu_id;
 
+#ifdef CONFIG_XEN
+        if (running_on_xen) {
+                extern void xen_send_ipi (int cpu, int vec);
+                xen_send_ipi (cpu, vector);
+                return;
+        }
+#endif /* CONFIG_XEN */
+
 #ifdef CONFIG_SMP
        phys_cpu_id = cpu_physical_id(cpu);
 #else
index 2adcd3ed568afdacb2e8afa577396c61be5a864a..a1be624556661c7234f14aadc7e2978e72c4b322 100644 (file)
@@ -341,3 +341,13 @@ GLOBAL_ENTRY(xen_set_eflag)
        br.ret.sptk.many rp
 END(xen_set_eflag)
 #endif
+
+GLOBAL_ENTRY(xen_send_ipi)
+        mov r14=r32
+        mov r15=r33
+        mov r2=0x380
+        break 0x1000
+        ;;
+        br.ret.sptk.many rp
+        ;;
+END(xen_send_ipi)
index 9f45769510d86b79ac0f0ed6bce3c232059a65e7..36894c12de50d7b1637ae7ecb464c2fc006ce43e 100644 (file)
@@ -94,9 +94,24 @@ unsigned long dom_fw_setup(struct domain *d, const char *args, int arglen)
 
 /* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */
 
-#define NUM_EFI_SYS_TABLES 6
-# define NUM_MEM_DESCS 5
+/* Set IP and GR1 of not yet initialized vcpu.  */
+static void
+set_os_boot_rendez (struct domain *d, unsigned long pc, unsigned long gr1)
+{
+       struct vcpu *v;
+       int i;
 
+       printf ("set_os_boot_rendez: %lx %lx\n", pc, gr1);
+       for (i = 1; i < MAX_VIRT_CPUS; i++) {
+               v = d->vcpu[i];
+               if (v != NULL
+                   && !test_bit(_VCPUF_initialised, &v->vcpu_flags)) {
+                       struct pt_regs *regs = vcpu_regs (v);
+                       regs->cr_iip = pc;
+                       regs->r1 = gr1;
+               }
+       }
+}
 
 struct sal_ret_values
 sal_emulator (long index, unsigned long in1, unsigned long in2,
@@ -155,7 +170,18 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
                     printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
                break;
            case SAL_SET_VECTORS:
-               printf("*** CALLED SAL_SET_VECTORS.  IGNORED...\n");
+               if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
+                       if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
+                               /* Sanity check: cs_length1 must be 0,
+                                  second vector is reserved.  */
+                               status = -2;
+                       }
+                       else
+                               set_os_boot_rendez (current->domain, in2, in3);
+               }
+               else
+                       printf("*** CALLED SAL_SET_VECTORS %lu.  IGNORED...\n",
+                              in1);
                break;
            case SAL_GET_STATE_INFO:
                /* No more info.  */
@@ -618,6 +644,9 @@ dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
        return;
 }
 
+#define NUM_EFI_SYS_TABLES 6
+#define NUM_MEM_DESCS  5
+
 static struct ia64_boot_param *
 dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size)
 {
@@ -625,8 +654,9 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        efi_runtime_services_t *efi_runtime;
        efi_config_table_t *efi_tables;
        struct ia64_sal_systab *sal_systab;
-       efi_memory_desc_t *efi_memmap, *md;
        struct ia64_sal_desc_entry_point *sal_ed;
+       struct ia64_sal_desc_ap_wakeup *sal_wakeup;
+       efi_memory_desc_t *efi_memmap, *md;
        struct ia64_boot_param *bp;
        unsigned long *pfn;
        unsigned char checksum = 0;
@@ -662,6 +692,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        efi_tables  = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables);
        sal_systab  = (void *) cp; cp += sizeof(*sal_systab);
        sal_ed      = (void *) cp; cp += sizeof(*sal_ed);
+       sal_wakeup  = (void *) cp; cp += sizeof(*sal_wakeup);
        efi_memmap  = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
        bp          = (void *) cp; cp += sizeof(*bp);
        pfn         = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
@@ -779,7 +810,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        sal_systab->size = sizeof(*sal_systab);
        sal_systab->sal_rev_minor = 1;
        sal_systab->sal_rev_major = 0;
-       sal_systab->entry_count = 1;
+       sal_systab->entry_count = 2;
 
        strcpy((char *)sal_systab->oem_id, "Xen/ia64");
        strcpy((char *)sal_systab->product_id, "Xen/ia64");
@@ -792,6 +823,11 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1);
        sal_ed->gp = 0;  // will be ignored
 
+       /* Fill an AP wakeup descriptor.  */
+       sal_wakeup->type = SAL_DESC_AP_WAKEUP;
+       sal_wakeup->mechanism = IA64_SAL_AP_EXTERNAL_INT;
+       sal_wakeup->vector = XEN_SAL_BOOT_RENDEZ_VEC;
+
        for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
                checksum += *cp;
 
index f0696cdbe73486fe70eff6eb44546b2db1ad3aa1..448112f842dd70077dabfdfb9fae16c7f1b8a640 100644 (file)
@@ -132,6 +132,65 @@ xen_hypercall (struct pt_regs *regs)
 }
 
 
+static void
+fw_hypercall_ipi (struct pt_regs *regs)
+{
+       int cpu = regs->r14;
+       int vector = regs->r15;
+       struct vcpu *targ;
+                   
+       if (0 && vector == 254)
+               printf ("send_ipi from %d to %d vector=%d\n",
+                       current->vcpu_id, cpu, vector);
+
+       if (cpu > MAX_VIRT_CPUS)
+               return;
+
+       targ = current->domain->vcpu[cpu];
+       if (targ == NULL)
+               return;
+
+       if (vector == XEN_SAL_BOOT_RENDEZ_VEC
+           && !test_bit(_VCPUF_initialised, &targ->vcpu_flags)) {
+               struct pt_regs *targ_regs = vcpu_regs (targ);
+               struct vcpu_guest_context c;
+               
+               printf ("arch_boot_vcpu: %p %p\n",
+                       (void *)targ_regs->cr_iip,
+                       (void *)targ_regs->r1);
+               memset (&c, 0, sizeof (c));
+               /* Copy regs.  */
+               c.regs.cr_iip = targ_regs->cr_iip;
+               c.regs.r1 = targ_regs->r1;
+               
+               /* Copy from vcpu 0.  */
+               c.vcpu.evtchn_vector =
+                       current->domain->vcpu[0]->vcpu_info->arch.evtchn_vector;
+               if (arch_set_info_guest (targ, &c) != 0) {
+                       printf ("arch_boot_vcpu: failure\n");
+                       return;
+               }
+               if (test_and_clear_bit(_VCPUF_down,
+                                      &targ->vcpu_flags)) {
+                       vcpu_wake(targ);
+                       printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
+                               targ->vcpu_id, targ_regs->cr_iip);
+               }
+               else
+                       printf ("arch_boot_vcpu: huu, already awaken!");
+       }
+       else {
+               int running = test_bit(_VCPUF_running,
+                                      &targ->vcpu_flags);
+               
+               vcpu_pend_interrupt(targ, vector);
+               vcpu_unblock(targ);
+               if (running)
+                       smp_send_event_check_cpu(targ->processor);
+       }
+       return;
+}
+
 static int
 fw_hypercall (struct pt_regs *regs)
 {
@@ -232,6 +291,9 @@ fw_hypercall (struct pt_regs *regs)
                // FIXME: need fixes in efi.h from 2.6.9
                regs->r8 = EFI_UNSUPPORTED;
                break;
+           case FW_HYPERCALL_IPI:
+               fw_hypercall_ipi (regs);
+               break;
            default:
                printf("unknown ia64 fw hypercall %lx\n", regs->r2);
                regs->r8 = do_ni_hypercall();
index e5189719ac86fc991a0242cd7a35b008356f9018..4b48f3188355abf223b0ead8168b8840c2f1ebf6 100644 (file)
@@ -125,9 +125,14 @@ extern unsigned long dom_fw_setup(struct domain *, const char *, int);
 */
 #define FW_HYPERCALL_FIRST_ARCH                0x300UL
 
+#define FW_HYPERCALL_IPI               0x380UL
+
 /* Xen/ia64 user hypercalls.  Only used for debugging.  */
 #define FW_HYPERCALL_FIRST_USER                0xff00UL
 
+/* Interrupt vector used for os boot rendez vous.  */
+#define XEN_SAL_BOOT_RENDEZ_VEC        0xF3
+
 extern struct ia64_pal_retval xen_pal_emulator(UINT64, u64, u64, u64);
 extern struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7);
 extern struct ia64_pal_retval pal_emulator_static (unsigned long);